/**
 * 
 */
package net.sf.cldsql.dj.mvc;


import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.cldsql.dj.utl.DiException;

/**
 * SjUtl
 */
public class DiContextServletImpl implements DiContext {
    private Map<String,Cookie> cookieMap;
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    private Map<String, String[]> parameterMap;
    protected HttpServlet serverLet;

    public DiContextServletImpl (HttpServletRequest request, HttpServletResponse response, HttpServlet serverLet) {
        this.request = request;
        this.response = response;
        this.serverLet = serverLet;
    }
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getParameterMap()
     */
    public Map<String, String[]> getParameterMap() {
        if (this.parameterMap == null) {
            this.parameterMap = new HashMap<String, String[]>();
            for (Enumeration names = request.getParameterNames(); names.hasMoreElements(); ) {
                String name = (String) names.nextElement();
                this.parameterMap.put(name, this.getParameterValues(name));
            }
        }
        return this.parameterMap;
    }
    
    private String[] getParameterValues(String name) {
        String[] ret = null;
        String[] values = this.request.getParameterValues(name);
        if (values != null) {
            ret = new String[values.length];
            for (int i = 0; i < values.length; i ++) {
                ret[i] = decode(values[i]);
            }
        }
        return ret;
    }
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getParam(java.lang.String)
     */
    @Override
    public String getParam(String name) {
        return decode(this.request.getParameter(name));
    }
    private String decode(String value) {
        String ret = value;
        String charsetName;
        // setCharacterEncoding will not effect the URL ISO-8859-1 encoding when GET method called
        if (value != null 
                && this.request.getMethod().equals("GET") 
                && (charsetName = this.getResponse().getCharacterEncoding()) != null) {
            try {
                ret = new String(value.getBytes("ISO-8859-1"), charsetName);
            } catch (UnsupportedEncodingException e) {
                throw new DiException(e);
            }
        }
        return ret;
    }
    
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getPathInfo()
     */
    public String getPathInfo() {
        return request.getPathInfo();
    }
    
    private String method;
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getMethod()
     */
    public String getMethod() {
        return method != null ? method : request.getMethod();
    }
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#setMethod(java.lang.String)
     */
    public void setMethod(String method) {
        this.method = method;
    }
    
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getSession(boolean)
     */
    @Override
    public DiSession getSession(boolean isNew) {
        HttpSession httpSession = this.request.getSession(isNew);
        DiSession session = httpSession != null? new DiSessionServletImpl(httpSession) : null;
        return session;
    }

    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#addCookie(java.lang.String, java.lang.String, java.lang.String, java.lang.String, int)
     */
    public void addCookie(String name, String value, String domain, String path, int maxAge){
        Cookie cookie = new Cookie(name,value);
        if (domain != null) {
            cookie.setDomain(domain);
        }
        cookie.setPath(path == null ? "/" : path);
        if(maxAge > 0) {
            cookie.setMaxAge(maxAge);
        }
        this.response.addCookie(cookie);
    }
    
    private Cookie getCookie(String name){
        if (cookieMap == null) {
            cookieMap = readCookieMap();
        }
        if(cookieMap.containsKey(name)){
            Cookie cookie = (Cookie)cookieMap.get(name);
            return cookie;
        }else{
            return null;
        }   
    }
    
    private Map<String,Cookie> readCookieMap(){  
        cookieMap = new HashMap<String,Cookie>();
        Cookie[] cookies = request.getCookies();
        if(null != cookies){
            for(Cookie cookie : cookies){
                cookieMap.put(cookie.getName(), cookie);
            }
        }
        return cookieMap;
    }
    
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getCookieValue(java.lang.String)
     */
    public HashMap<String, Object> getCookieValue(String name) {
        final Cookie cookie = getCookie(name);
        if (cookie != null) {
            return new HashMap<String, Object>() {
                private static final long serialVersionUID = 1L;
            {
                put("name", cookie.getName());
                put("value", cookie.getValue());
                put("domain", cookie.getDomain());
                put("path", cookie.getPath());
                put("maxAge", cookie.getMaxAge());
                put("comment", cookie.getComment());
            }};
        } else {
            return null;
        }
    }

    public void forward(String name) {
        try {
            request.getRequestDispatcher(name).forward(request, response);
        } catch (ServletException e) {
            throw new DiException(e);
        } catch (IOException e) {
            throw new DiException(e);
        }
    }
    public void include(String name) {
        try {
            request.getRequestDispatcher(name).include(request, response);
        } catch (ServletException e) {
            throw new DiException(e);
        } catch (IOException e) {
            throw new DiException(e);
        }
    }
    public void sendRedirect(String name) {
        try {
            response.sendRedirect(name);
        } catch (IOException e) {
            throw new DiException(e);
        }
    }
    /**
     * @return request
     */
    public HttpServletRequest getRequest() {
        return request;
    }
    /**
     * @return response
     */
    public HttpServletResponse getResponse() {
        return response;
    }
    /* (non-Javadoc)
     * @see net.sf.cldsql.dj.mvc.DiContext#getServerLet()
     */
    public HttpServlet getServerLet() {
        return this.serverLet;
    }
}
